package main

import (
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	"image"
	"image/color"
	"log"
	"strconv"
	"sunibas.cn/DIP/Utils"
)

var tmpImgPath0, tmpImgPath1, tmpImgPath2, imgPath = Utils.SetAllPath()

//var tmpImgPath0 = "E:\\研究生作业\\DIP\\tmp0.pgm"
//var tmpImgPath1 = "E:\\研究生作业\\DIP\\tmp1.pgm"
//var tmpImgPath2 = "E:\\研究生作业\\DIP\\tmp2.pgm"
////var imgPath = "E:\\研究生作业\\DIP\\test.pgm"
//var imgPath = "E:\\研究生作业\\DIP\\Chapter2_1.pgm"
var w fyne.Window
var pgm Utils.PgmFile
var img1, img2, img3, img4 *canvas.Image
var conclusionText *canvas.Text
var mseContent *canvas.Text

//var rmseContent * canvas.Text
var psnrContent *canvas.Text
var ssimContent *canvas.Text

var maxContent *canvas.Text
var MeanContent *canvas.Text
var MedianContent *canvas.Text
var CoverBoxContent *canvas.Text

//var max1Content *canvas.Text
//var Mean1Content *canvas.Text
//var Median1Content *canvas.Text
//var max2Content *canvas.Text
//var Mean2Content *canvas.Text
//var Median2Content *canvas.Text

func main() {
	//pgm = Utils.PgmFile{
	//	FileName: imgPath,
	//}
	//pgm.OpenFile()
	//fmt.Println(pgm.ToString())

	buildApp()
}

// 这里开始是 采样方法 的内容的界面设计
var methods = Utils.InterpolationMethods
var currentMethod = 0

func methodDialog() {
	tmpMethod := -1
	selectItem := widget.NewSelect(methods, func(s string) {
		for i, m := range methods {
			if s == m {
				tmpMethod = i
				break
			}
		}
	})
	selectItem.SetSelectedIndex(currentMethod)
	content := container.NewVBox(selectItem)
	dig := dialog.NewCustom("Select Method", "close", content, w)
	dig.SetOnClosed(func() {
		if tmpMethod != -1 {
			currentMethod = tmpMethod
			go rotaImage()
			refreshToolbar()
		}
	})
	dig.Show()
}

// 采样方法 的内容的界面设计到这里结束

// 选择图片
var imgs = []string{
	"src pgm",
	"myexample1",
	"myexample2",
}
var currentImage = 0
var imageExamples = []func() Utils.PgmFile{
	Utils.ZyExample,
	Utils.MyExample1,
	Utils.MyExample2,
}

func imageDialog() {
	tmpImage := -1
	selectItem := widget.NewSelect(imgs, func(s string) {
		for i, m := range imgs {
			if s == m {
				tmpImage = i
				break
			}
		}
	})
	selectItem.SetSelectedIndex(currentImage)
	content := container.NewVBox(selectItem)
	dig := dialog.NewCustom("Select Method", "close", content, w)
	dig.SetOnClosed(func() {
		if tmpImage != -1 {
			currentImage = tmpImage
			refreshApp()
		}
	})
	dig.Show()
}

// 选择图片结束

// 旋转角度相关 开始
var rotateDegree = 0
var img2Label *canvas.Text

func rotaImage() {
	if rotateDegree == 0 {
		return
	}
	refreshToolbar()
	img2Label.Text = "rotate : " + strconv.Itoa(rotateDegree) + "°"
	img2Label.Refresh()
	image2 := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{pgm.SeqWidth, pgm.SeqWidth}})
	copyImg := Utils.RotaGrayImage(pgm.Img, pgm.Width, pgm.Height, rotateDegree, pgm.SeqWidth, Utils.InterpolationMethods[currentMethod])
	Utils.SaveAsPgm(copyImg, pgm.SeqWidth, pgm.SeqWidth, tmpImgPath0)
	fx, fy, tx, ty, width, height := Utils.GetMaxBox(copyImg, pgm.SeqWidth, pgm.SeqWidth)
	CoverBoxContent.Text = "Box Size: width = " + strconv.Itoa(width) + "    height = " + strconv.Itoa(height)
	CoverBoxContent.Refresh()
	fx--
	fy--
	tx++
	ty++
	for i := 0; i < pgm.SeqWidth; i++ {
		for j := 0; j < pgm.SeqWidth; j++ {
			if i == fy || i == tx {
				for k := fx; k < tx; k++ {
					image2.Set(i, k, color.Gray{
						Y: 128,
					})
				}
				break
			} else if j == fx || j == tx {
				if i > fy && i < ty {
					image2.Set(i, j, color.Gray{
						Y: 128,
					})
				}
			} else {
				image2.Set(i, j, color.Gray{
					Y: copyImg[i+j*pgm.SeqWidth],
				})
			}
		}
	}
	img2.Image = image2
	img2.Refresh()

	image3 := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{pgm.SeqWidth, pgm.SeqWidth}})
	copyImg = Utils.RotaGrayImage(copyImg, pgm.SeqWidth, pgm.SeqWidth, -rotateDegree, pgm.SeqWidth, Utils.InterpolationMethods[currentMethod])
	pgm.ResetCutXY()
	ci := pgm.CutToSize(copyImg)
	halfWidth := (pgm.SeqWidth - pgm.Width) / 2
	halfHeight := (pgm.SeqWidth - pgm.Height) / 2
	updateCompare(ci)
	for i := 0; i < pgm.Width; i++ {
		for j := 0; j < pgm.Height; j++ {
			image3.Set(i+halfWidth, j+halfHeight, color.Gray{
				Y: ci[i+j*pgm.Width],
			})
		}
	}
	img3.Image = image3
	img3.Refresh()
	Utils.SaveAsPgm(copyImg, pgm.SeqWidth, pgm.SeqWidth, tmpImgPath1)

	//copyImg = Utils.ImageCut(img1.Image,img2.Image,pgm.SeqWidth,pgm.SeqWidth)
	count, sum := 0, 0
	//var jicha byte = 0
	copyImg, count, sum, _ = pgm.Cut(ci)
	//jiChaContent.Text = strconv.Itoa(int(jicha))
	//jiChaContent.Refresh()
	cx, cy := pgm.GetCutXY()
	fmt.Println("pgm.CutX = " + strconv.Itoa(cx) + "\tpgm.CutY = " + strconv.Itoa(cy))
	fmt.Println("halfWidth = " + strconv.Itoa(halfWidth) + "\thalfHeight = " + strconv.Itoa(halfHeight))
	conclusionText.Text = "dps: " + strconv.Itoa(count) + "  sum of dps: " + strconv.Itoa(sum) + "  dx: " + strconv.Itoa(cx-halfWidth) + "  dy: " + strconv.Itoa(cy-halfHeight)
	conclusionText.Refresh()
	Utils.SaveAsPgm(copyImg, pgm.SeqWidth, pgm.SeqWidth, tmpImgPath2)
	//image4 := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{pgm.SeqWidth,pgm.SeqWidth }})
	image4 := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{pgm.SeqWidth, pgm.SeqWidth}})
	for i := 0; i < pgm.Width; i++ {
		for j := 0; j < pgm.Height; j++ {
			//image4.Set(i, j, color.Gray{
			//	Y: copyImg[i + j * pgm.SeqWidth],
			//})
			t := copyImg[i+j*pgm.Width]
			if t <= 1 {
				image4.Set(i+halfWidth, j+halfHeight, color.RGBA{
					R: 0,
					G: 0,
					B: 0,
					A: 255,
				})
			} else if t < 80 {
				image4.Set(i+halfWidth, j+halfHeight, color.RGBA{
					R: t*2 + 80,
					G: 0,
					B: 0,
					A: 255,
				})
			} else if t < 160 {
				image4.Set(i+halfWidth, j+halfHeight, color.RGBA{
					R: 0,
					G: (t-80)*2 + 80,
					B: 0,
					A: 255,
				})
			} else {
				image4.Set(i+halfWidth, j+halfHeight, color.RGBA{
					R: 0,
					G: 0,
					B: (t-160)*2 + 80,
					A: 255,
				})
			}
		}
	}
	img4.Image = image4
	img4.Refresh()
}
func updateCompare(copyImg []byte) {
	//ccs := Utils.CommonCompare(pgm.Img, copyImg)
	//
	//max1Content.Text = "max1:" + strconv.Itoa(int(ccs.Max1))
	//max1Content.Refresh()
	//Mean1Content.Text = "mean1:" + strconv.FormatFloat(ccs.Avg1, 'f', 1, 64)
	//Mean1Content.Refresh()
	//Median1Content.Text = "median1:" + strconv.FormatFloat(ccs.Mid1, 'f', 1, 64)
	//Median1Content.Refresh()
	//
	//max2Content.Text = "max2:" + strconv.Itoa(int(ccs.Max2))
	//max2Content.Refresh()
	//Mean2Content.Text = "mean2:" + strconv.FormatFloat(ccs.Avg2, 'f', 1, 64)
	//Mean2Content.Refresh()
	//Median2Content.Text = "median2:" + strconv.FormatFloat(ccs.Mid2, 'f', 1, 64)
	//Median2Content.Refresh()
	max, median, mean := Utils.GetMaxMeanMeidan(pgm.Img, copyImg)
	maxContent.Text = "max:" + strconv.Itoa(max)
	maxContent.Refresh()
	MeanContent.Text = "mean:" + strconv.FormatFloat(mean, 'f', 1, 64)
	MeanContent.Refresh()
	MedianContent.Text = "median:" + strconv.Itoa(median)
	MedianContent.Refresh()

	ci := Utils.Bytes2Float64(copyImg)
	simg := Utils.Bytes2Float64(pgm.Img)
	mse := Utils.MSE(simg, ci)
	mseContent.Text = "mse:" + strconv.FormatFloat(mse, 'f', 3, 64)
	mseContent.Refresh()

	//rmse := math.Pow(mse,2)
	//rmseContent.Text = "rmse:" + strconv.FormatFloat(rmse,'f',5,64)
	//rmseContent.Refresh()

	psnr := Utils.PSNR(simg, ci)
	psnrContent.Text = "psnr:" + strconv.FormatFloat(psnr, 'f', 3, 64)
	psnrContent.Refresh()

	ssim := Utils.SSIM(simg, ci)
	ssimContent.Text = "ssim:" + strconv.FormatFloat(ssim, 'f', 3, 64)
	ssimContent.Refresh()

	// 不知道为什么结果一直是 1
	//msssim := Utils.MSSSIM(simg,ci,pgm.Width,pgm.Height)
	//msssimContent.Text = "ms-ssim:" + strconv.FormatFloat(msssim,'f',5,64)
	//msssimContent.Refresh()
	//
	//sam := Utils.SAM(simg,ci)
	//samContent.Text = "sam:" + strconv.FormatFloat(sam,'f',5,64)
	//samContent.Refresh()
}
func rotateDialog() {
	tmpDegree := -200
	degreeEntry := widget.NewEntry()
	degreeEntry.SetPlaceHolder("input name")
	degreeEntry.OnChanged = func(content string) {
		if degreeEntry.Text != "" {
			if n, err := strconv.ParseInt(content, 10, 16); err != nil {
				degreeEntry.Text = ""
				dialog.NewInformation("Error", err.Error(), w).Show()
			} else {
				if n > 360 || n < -360 {
					dialog.NewInformation("Error", "degree required in range(-180,180)", w).Show()
					degreeEntry.Text = ""
				} else {
					tmpDegree = int(n)
				}
			}
		}
	}
	content := container.NewHBox(widget.NewLabel("Degree"), layout.NewSpacer(), degreeEntry)
	dig := dialog.NewCustom("Select Method", "close", content, w)
	dig.SetOnClosed(func() {
		if tmpDegree != -200 {
			rotateDegree = tmpDegree
			refreshToolbar()
			rotaImage()
		}
	})
	dig.Show()
}

// 选择角度相关 结束

var toolbar *widget.Toolbar

func refreshToolbar() {
	if toolbar != nil {
		toolbar.Items[2] = Utils.NewToolbarActionOnlyLable("method:"+methods[currentMethod], func() {
			methodDialog()
		})
		toolbar.Items[0] = Utils.NewToolbarActionOnlyLable("degree:"+strconv.Itoa(rotateDegree), func() {
			rotateDialog()
		}) // 2
		toolbar.Items[4] = Utils.NewToolbarActionOnlyLable("img:"+imgs[currentImage], func() {
			imageDialog()
		})
		toolbar.Refresh()
	} else {
		toolbar = widget.NewToolbar(
			Utils.NewToolbarActionOnlyLable("cur deg:"+strconv.Itoa(rotateDegree), func() {
				rotateDialog()
			}), // 0
			widget.NewToolbarSeparator(), // 1
			Utils.NewToolbarActionOnlyLable("method:"+methods[currentMethod], func() {
				methodDialog()
			}), // 2
			widget.NewToolbarSeparator(), // 3
			Utils.NewToolbarActionOnlyLable("img:"+imgs[currentImage], func() {
				imageDialog()
			}), // 4
			widget.NewToolbarSpacer(), // 5
			widget.NewToolbarAction(theme.HelpIcon(), func() {
				log.Println("Display help")
			}), // 6
		)
		toolbar.Refresh()
	}
}

func setContainer() *fyne.Container {
	pgm = imageExamples[currentImage]()
	fmt.Println("Image Info:" +
		"\n\timg.width :\t" + strconv.Itoa(pgm.Width) +
		"\n\timg.height :\t" + strconv.Itoa(pgm.Height) +
		"\n\timg.SeqWidth :\t" + strconv.Itoa(pgm.SeqWidth))
	refreshToolbar()
	halfWidth := (pgm.SeqWidth - pgm.Width) / 2
	halfHeight := (pgm.SeqWidth - pgm.Height) / 2
	image1 := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{pgm.SeqWidth, pgm.SeqWidth}})
	for i := 0; i < pgm.Width; i++ {
		for j := 0; j < pgm.Height; j++ {
			image1.Set(i+halfWidth, j+halfHeight, color.Gray{
				Y: pgm.Img[i+j*pgm.Width],
			})
		}
	}
	img1 = canvas.NewImageFromImage(image1)
	img1.FillMode = canvas.ImageFillOriginal
	img1Label := canvas.NewText("Orign", color.Black)

	image2 := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{pgm.SeqWidth, pgm.SeqWidth}})
	img2 = canvas.NewImageFromImage(image2)
	img2.FillMode = canvas.ImageFillOriginal
	img2Label = canvas.NewText("Rotate", color.Black)

	image3 := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{pgm.SeqWidth, pgm.SeqWidth}})
	img3 = canvas.NewImageFromImage(image3)
	img3.FillMode = canvas.ImageFillOriginal
	img3Label := canvas.NewText("Rotate Back", color.Black)

	image4 := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{pgm.SeqWidth, pgm.SeqWidth}})
	img4 = canvas.NewImageFromImage(image4)
	img4.FillMode = canvas.ImageFillOriginal
	img4Label := canvas.NewText("Cut", color.Black)

	conclusionText = canvas.NewText("", color.Black)
	mseContent = canvas.NewText("", color.Black)
	//rmseContent = canvas.NewText("",color.Black)
	psnrContent = canvas.NewText("", color.Black)
	ssimContent = canvas.NewText("", color.Black)

	maxContent = canvas.NewText("", color.Black)
	MeanContent = canvas.NewText("", color.Black)
	MedianContent = canvas.NewText("", color.Black)
	CoverBoxContent = canvas.NewText("", color.Black)

	//max1Content = canvas.NewText("", color.Black)
	//Mean1Content = canvas.NewText("", color.Black)
	//Median1Content = canvas.NewText("", color.Black)
	//max2Content = canvas.NewText("", color.Black)
	//Mean2Content = canvas.NewText("", color.Black)
	//Median2Content = canvas.NewText("", color.Black)

	content := fyne.NewContainerWithLayout(
		layout.NewBorderLayout(toolbar, nil, nil, nil),
		toolbar,
		fyne.NewContainerWithLayout(
			layout.NewVBoxLayout(),
			container.NewHBox(img1, img2),
			container.NewGridWrap(fyne.NewSize(float32(pgm.SeqWidth), 15),
				container.NewCenter(img1Label),
				container.NewCenter(img2Label)),
			container.NewHBox(img3, img4),
			container.NewGridWrap(fyne.NewSize(float32(pgm.SeqWidth), 15),
				container.NewCenter(img3Label),
				container.NewCenter(img4Label)),

			container.NewGridWrap(fyne.NewSize(float32(pgm.SeqWidth*2/3), 15),
				container.NewCenter(mseContent),
				container.NewCenter(psnrContent),
				container.NewCenter(ssimContent),
			),
			container.NewGridWrap(fyne.NewSize(float32(pgm.SeqWidth*2/3), 15),
				container.NewCenter(maxContent),
				container.NewCenter(MeanContent),
				container.NewCenter(MedianContent),
			),
			//container.NewGridWrap(fyne.NewSize(float32(pgm.SeqWidth*2/3), 15),
			//	container.NewCenter(max1Content),
			//	container.NewCenter(Mean1Content),
			//	container.NewCenter(Median1Content),
			//),
			//container.NewGridWrap(fyne.NewSize(float32(pgm.SeqWidth*2/3), 15),
			//	container.NewCenter(max2Content),
			//	container.NewCenter(Mean2Content),
			//	container.NewCenter(Median2Content),
			//),

			//container.NewVBox(container.NewCenter(conclusionText)),
			container.NewVBox(container.NewCenter(CoverBoxContent)),
		))
	return content
}
func refreshApp() {
	w.SetContent(setContainer())
	w.SetFullScreen(false)
	w.SetFixedSize(false)
}
func buildApp() {
	a := app.New()
	w = a.NewWindow("DIP 2_1")
	w.SetPadded(false)
	refreshApp()
	w.ShowAndRun()
}
